//-------------------------------------------------------------------
//	Copyright (c) 2012-2014 Zhirnov Andrey
//	This file is part of the "UXGEN-ES" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#pragma once

#include "Physics2D/Objects/Utils.h"

namespace Engine
{
namespace Physics2D
{

	//
	// Physics Object
	//

	class PhysicsObject
	{
	// types
	public:
		struct EPhysicsObj
		{
			enum type
			{
				UNKNOWN = 0,
				RIGID_BODY,
				TRIGGER,
			};
		};

		struct EBody
		{
			enum type
			{
				STATIC		= b2_staticBody,
				KINEMATIC	= b2_kinematicBody,
				DYNAMIC		= b2_dynamicBody,
			};
		};


	// variables
	protected:
		Ptr< b2Body >				_body;
		const EPhysicsObj::type		_objType;


	// methods
	protected:
		PhysicsObject (EPhysicsObj::type type) : _objType(type)	{}

	public:
		PhysicsObject () : _objType( EPhysicsObj::RIGID_BODY )	{}
		
		virtual ~PhysicsObject () {}
		

		void Create (b2World *world, const b2BodyDef &bodyDef = b2BodyDef())
		{
			CHECK_ERR( _body.IsNull(), );

			b2BodyDef body_def = bodyDef;
			body_def.userData = this;

			_body = world->CreateBody( &body_def );
		}

		void SetTransform (const vec2 &pos, float angleRad)		{ _body->SetTransform( Utils::Vec2( pos ), angleRad ); }

		// velocity
		void SetLinearVelocity (const vec2 &vel)				{ _body->SetLinearVelocity( Utils::Vec2( vel ) ); }
		void SetAngularVelocity (float omegaRadPerSec)			{ _body->SetAngularVelocity( omegaRadPerSec ); }

		// force
		void ApplyForce (const vec2 &force, const vec2 &point)	{ _body->ApplyForce( Utils::Vec2( force ), Utils::Vec2( point ) ); }
		void ApplyForceToCenter (const vec2 &force)				{ _body->ApplyForceToCenter( Utils::Vec2( force ) ); }
		void ApplyTorque (float torque)							{ _body->ApplyTorque( torque ); }
		
		// impulse
		void ApplyLinearImpulse (const vec2 &impulse, const vec2 &point)	{ _body->ApplyLinearImpulse( Utils::Vec2( impulse ), Utils::Vec2( point ) ); }
		void ApplyAngularImpulse (float impulse)				{ _body->ApplyAngularImpulse( impulse ); }

		// mass
		void SetMass (float mass, const vec2 &center = vec2(), float inertia = 0.0f)
		{
			b2MassData	data;

			data.mass	= mass;
			data.center	= Utils::Vec2( center );
			data.I		= inertia;

			_body->SetMassData( &data );
		}


		b2Body *		GetBody ()						{ return _body; }

		float			GetMass ()				const	{ return _body->GetMass(); }
		float			GetInertia ()			const	{ return _body->GetInertia(); }

		vec2 const &	GetPosition ()			const	{ return Utils::Vec2( _body->GetPosition() ); }
		vec2 const &	GetRotation ()			const	{ return Utils::SinCos( _body->GetTransform().q ); }
		float			GetAngle ()				const	{ return _body->GetAngle(); }

		vec2			GetLinearVelocity ()	const	{ return Utils::Vec2( _body->GetLinearVelocity() ); }
		float			GetAngularVelocity ()	const	{ return _body->GetAngularVelocity(); }

		EBody::type		GetBodyType ()			const	{ return (EBody::type) _body->GetType(); }

		EPhysicsObj::type	GetType ()			const	{ return _objType; }
	};


}	// Physics2D
}	// Engine